package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
@Slf4j
public class AutoFillAspect {


    //切入点表达式
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillAspectPointcut() {
    }

    //通知
    @Before("autoFillAspectPointcut()")
    public void autoFill(JoinPoint joinPoint) {
        //这里的公共字段指的是create_time,update_time,create_user,update_user这四个字段
        //由于在每个模块中都会存在这样的代码,所以就通过自动填充公共字段进行赋值操作
        //插入一个数据(也就是执行insert)的时候这四个属性都会赋值,但是执行修改操作的时候就只会给update_time,update_user
        //这两个属性赋值
        //所以@AutoFill中存在这两个数据库操作的类型一个式INSERT一个是UPDATE,这连个类型都用了枚举进行了封装

        log.info("开始进行公共字段自动填充....");
        //1.从拦截到的方法中获取到@AutoFill注解的数据库操作类型
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        AutoFill autoFill = signature.getMethod()//获取到方法
                .getAnnotation(AutoFill.class);//获取到方法上的AutoFill注解对象
        OperationType value = autoFill.value();//通过注解获取到value值

        //2.获取到方法中的实体类,将实体类中的create_time等属性进行赋值操作
        Object[] args = joinPoint.getArgs();//获取到方法中所有的参数,这里是一个参数集合,我们约定在mapper中insert和update方法中的第一个参数一定要是实体类(就是要有那四个属性的类)
        Object entity = args[0];//获取到实体类
        if (args == null || args.length == 0)//判空
        {
            return;
        }

        //3.准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long id = BaseContext.getCurrentId();
        //4.根据当前方法上的数据库操作类型进行赋值操作,为对应的属性进行赋值,通过反射进行赋值操作
        if (value == OperationType.INSERT) {
            //如果是Insert类型的话4个属性都要进行赋值操作
            try {
                //获取到实体类中的set方法
                Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //
            setCreateTime.invoke(entity,now);
            setCreateUser.invoke(entity,id);
            setUpdateTime.invoke(entity,now);
            setUpdateUser.invoke(entity,id);
            } catch (Exception e) {
                e.printStackTrace();
            }


        } else if (value == OperationType.UPDATE) {
            //如果是Update类型的话update_time和update_user2个属性要进行赋值操作
            try {
                //获取到实体类中的set方法
                Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,id);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }

}
